﻿/*********************************************************************************************************************
 * COPYRIGHT NOTICE
 * Copyright (c) 2018,逐飞科技
 * All rights reserved.
 * 技术讨论QQ群：一群：179029047(已满)  二群：244861897
 *
 * 以下所有内容版权均属逐飞科技所有，未经允许不得用于商业用途，
 * 欢迎各位使用并传播本程序，修改内容时必须保留逐飞科技的版权声明。
 *
 * @file       		TFT
 * @company	   		成都逐飞科技有限公司
 * @author     		逐飞科技(QQ3184284598)
 * @version    		查看doc内version文件 版本说明
 * @Software 		IAR 8.3 or MDK 5.26
 * @Taobao   		https://seekfree.taobao.com/
 * @date       		2018-05-24
 * @note
					接线定义：
					------------------------------------
						模块管脚            单片机管脚
						SCL                 查看TFT_SCL宏定义的引脚     硬件SPI引脚不可随意切换
						SDA                 查看TFT_SDA宏定义的引脚     硬件SPI引脚不可随意切换
						RES                 查看REST_PIN宏定义的引脚
						DC                  查看DC_PIN宏定义的引脚
						CS                  查看TFT_CS宏定义的引脚      硬件SPI引脚不可随意切换

						电源引脚
						BL  3.3V电源（背光控制引脚，也可以接PWM来控制亮度）
						VCC 3.3V电源
						GND 电源地
						最大分辨率128*160
					------------------------------------

 ********************************************************************************************************************/

#include "stdafx.h"
#include <stdarg.h>
#include "My_Key.h"
#include "My_Main.h"
#include "SEEKFREE_18TFT.h"
#include "SEEKFREE_FONT.h"
#include"TFT_Bottom.H"


int TFT_Pos_X, TFT_Pos_Y,TFT_Pos_X_End,TFT_Pos_Y_End;

//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
//-----------------------------------                                               ---------------------------------
//----------------------------------- 以下为用户无需关心的函数，用户可调用函数在300行后 ---------------------------------
//-----------------------------------                                               ---------------------------------
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------

void lcd_writedata_16bit(HBRUSH color)	//向液晶屏写一个16位数据
{
	SelectObject(PictureDC, color);
	Rectangle(PictureDC, TFT_Pos_X, TFT_Pos_Y,
		TFT_Pos_X + POINT_SIZE, TFT_Pos_Y+ POINT_SIZE);

	if(TFT_Pos_X<TFT_Pos_X_End)
		TFT_Pos_X+=POINT_SIZE;
}

uint8 number_conversion_ascii(uint32 dat, int8* p, uint8 neg_type, uint8 radix)
{
    int32   neg_dat;
    uint32  pos_dat;
    uint8   temp_data = 0;
    uint8   valid_num = 0;

    if (neg_type)
    {
        neg_dat = (int32)dat;
        if (neg_dat < 0)   neg_dat = -neg_dat;
        while (1)
        {
            *p = neg_dat % radix + '0';
            neg_dat = neg_dat / radix;
            valid_num++;

            if (!neg_dat) break;
            p++;
        }
    }
    else
    {
        pos_dat = dat;
        while (1)
        {
            temp_data = pos_dat % radix;
            if (10 <= temp_data) temp_data += 'A' - 10;
            else                temp_data += '0';

            *p = temp_data;

            pos_dat = pos_dat / radix;
            valid_num++;

            if (!pos_dat) break;
            p++;
        }
    }
    return valid_num;
}

void printf_reverse_order(int8* d_buff, uint32 len)
{
    uint32 i;
    int8  temp_data;
    for (i = 0; i < len / 2; i++)
    {
        temp_data = d_buff[len - 1 - i];
        d_buff[len - 1 - i] = d_buff[i];
        d_buff[i] = temp_data;
    }
}

uint32 zf_sprintf(int8* buff, const int8* format, ...)
{
    uint32 buff_len = 0;
    va_list arg;
    va_start(arg, format);

    while (*format)
    {
        int8 ret = *format;
        if (ret == '%')
        {
            switch (*++format)
            {
            case 'a':// ĘŽÁů˝řÖĆpźĆĘýˇ¨Ęäłö¸ĄľăĘý ÔÝÎ´ĘľĎÖ
            {


            }break;


            case 'c':// Ňť¸ö×Öˇű
            {
                int8 ch = (int8)va_arg(arg, uint32);
                *buff = ch;
                buff++;
                buff_len++;

            }break;


            case 'd':
            case 'i':// ÓĐˇűşĹĘŽ˝řÖĆŐűĘý
            {
                int8 vstr[33];
                int32 ival = (int32)va_arg(arg, int32);
                uint8 vlen = number_conversion_ascii((uint32)ival, vstr, 1, 10);

                if (ival < 0)
                {
                    vstr[vlen] = '-';
                    vlen++;
                }
                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff += vlen;
                buff_len += vlen;


            }break;

            case 'f':// ¸ĄľăĘýŁŹĘäłöĐĄĘýľăşóÁůÎť  ˛ťÄÜÖ¸ś¨ĘäłöžŤśČ
            case 'F':// ¸ĄľăĘýŁŹĘäłöĐĄĘýľăşóÁůÎť  ˛ťÄÜÖ¸ś¨ĘäłöžŤśČ
            {
                int8 vstr[33];
                double ival = (double)va_arg(arg, double);
                uint8 vlen = number_conversion_ascii((uint32)(int32)ival, vstr, 1, 10);

                if (ival < 0)
                {
                    vstr[vlen] = '-';
                    vlen++;
                }
                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff += vlen;
                buff_len += vlen;

                ival = ((double)ival - (int32)ival) * 1000000;
                if (ival)
                {
                    vlen = number_conversion_ascii((uint32)(int32)ival, vstr, 1, 10);
                }
                else
                {
                    vstr[0] = vstr[1] = vstr[2] = vstr[3] = vstr[4] = vstr[5] = '0';
                    vlen = 6;
                }

                while (6 > vlen)
                {
                    vstr[vlen] = '0';
                    vlen++;
                }

                vstr[vlen] = '.';
                vlen++;

                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff_len += vlen;

                break;
            }

            case 'u':// ÎŢˇűşĹĘŽ˝řÖĆŐűĘý
            {
                int8 vstr[33];
                uint32 ival = (uint32)va_arg(arg, uint32);
                uint8 vlen = number_conversion_ascii(ival, vstr, 0, 10);

                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff += vlen;
                buff_len += vlen;
            }break;

            case 'o':// ÎŢˇűşĹ°Ë˝řÖĆŐűĘý 
            {
                int8 vstr[33];
                uint32 ival = (uint32)va_arg(arg, uint32);
                uint8 vlen = number_conversion_ascii(ival, vstr, 0, 8);

                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff += vlen;
                buff_len += vlen;

            }break;

            case 'x':// ÎŢˇűşĹĘŽÁů˝řÖĆŐűĘý
            case 'X':// ÎŢˇűşĹĘŽÁů˝řÖĆŐűĘý
            {
                int8 vstr[33];
                uint32 ival = (uint32)va_arg(arg, uint32);
                uint8 vlen = number_conversion_ascii(ival, vstr, 0, 16);

                printf_reverse_order(vstr, vlen);
                memcpy(buff, vstr, vlen);
                buff += vlen;
                buff_len += vlen;
            }break;


            case 's':// ×Öˇű´Ž
            {
                int8* pc = va_arg(arg, int8*);
                while (*pc)
                {
                    *buff = *pc;
                    buff++;
                    buff_len++;
                    pc++;
                }
            }break;

            case 'p':// ŇÔ16˝řÖĆĐÎĘ˝ĘäłöÖ¸Őë
            {
                int8 vstr[33];
                uint32 ival = (uint32)va_arg(arg, uint32);
                uint8 vlen = number_conversion_ascii(ival, vstr, 0, 16);

                printf_reverse_order(vstr, 8);
                memcpy(buff, vstr, 8);
                buff += 8;
                buff_len += 8;

            }break;


            case '%':// Ęäłö×Öˇű% 
            {
                *buff = '%';
                buff++;
                buff_len++;
            }break;

            default:break;
            }
        }
        else
        {
            *buff = (int8)(*format);
            buff++;
            buff_len++;
        }
        format++;
    }
    va_end(arg);

    return buff_len;
}




//----------------------------------- 以下为用户用户可调用函数---------------------------------


 //-------------------------------------------------------------------------------------------------------------------
 //  @brief      液晶坐标设置
 //  @param      x_start     	坐标x方向的起点
 //  @param      y_start     	坐标y方向的起点
 //  @param      x_end       	坐标x方向的终点
 //  @param      y_end       	坐标y方向的终点
 //  @return     void
 //  @since      v1.0
 //  Sample usage:               lcd_set_region(0,0,10,10);// x、y的起点都是0，终点都是10
 //-------------------------------------------------------------------------------------------------------------------

void lcd_set_region(uint16 x_start, uint16 y_start, uint16 x_end, uint16 y_end)
{
	TFT_Pos_X = (x_start > 0) ? x_start: 0;
	TFT_Pos_Y = (y_start>0) ? y_start : 0;
	TFT_Pos_X_End = (x_end<TFT_X_MAX*POINT_SIZE)?x_end:TFT_X_MAX;
	TFT_Pos_Y_End = (y_end<TFT_Y_MAX*POINT_SIZE)?y_end:TFT_Y_MAX;
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶清屏函数
//  @param      color     		颜色设置
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_clear(YELLOW);// 全屏设置为黄色
//-------------------------------------------------------------------------------------------------------------------
void lcd_clear(HBRUSH color)
{

    SelectObject(PictureDC, color);
    Rectangle(PictureDC, 0, 0,
        TFT_X_MAX * POINT_SIZE, TFT_Y_MAX * POINT_SIZE);

}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶初始化
//  @return     void
//  @since      v1.0
//  Sample usage:               
//-------------------------------------------------------------------------------------------------------------------
void lcd_init(void)
{
    //这是一个空函数，因为没有必要去模拟
    //可以思考一下为什么要保留一个空函数
    //这个函数在什么地方会用到呢？
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶画点
//  @param      x     	        坐标x方向的起点
//  @param      y     	        坐标y方向的起点(注意，没有/16，范围为0~128）
//  @param      dat       	    需要显示的颜色
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_drawpoint(0,0,RED);  //坐标0,0画一个红色的点
//-------------------------------------------------------------------------------------------------------------------
void lcd_drawpoint(uint16 x, uint16 y, HBRUSH color)
{
    x *= POINT_SIZE, y *= POINT_SIZE;
	lcd_set_region(x, y, x, y);
	lcd_writedata_16bit(color);
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示字符
//  @param      x     	        坐标x方向的起点 参数范围 0 -（TFT_X_MAX-1）(注意坐标系：分辨率坐标系0-128、0-160）
//  @param      y     	        坐标y方向的起点 参数范围 0 -（TFT_Y_MAX-1）
//  @param      dat       	    需要显示的字符
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showchar(0,0,'x');//坐标0,0写一个字符x,注意这里的y没有除以16，可以取0~128
//-------------------------------------------------------------------------------------------------------------------
void lcd_showchar(uint16 x, uint16 y, uint8 dat)
{
	unsigned char i, j;
	unsigned char temp;

	x *= POINT_SIZE, y *= POINT_SIZE;	//通过乘法转换为放缩坐标系（实际坐标，0-128*POINT_SIZE)

	for (i = 0; i < 16; i++)
	{
		lcd_set_region(x, y + i*POINT_SIZE, x + 7*POINT_SIZE, y + i*POINT_SIZE);
		temp = tft_ascii[dat - 32][i];//减32因为是取模是从空格开始取得 空格在ascii中序号是32
		for (j = 0; j < 8; j++)
		{
			if (temp & 0x01)	lcd_writedata_16bit(PENCOLOR);
			else			lcd_writedata_16bit(BGCOLOR);
			temp >>= 1;
		}
	}
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示字符串
//  @param      x     	        坐标x方向的起点  参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点  参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的字符串
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showstr(0,0,"seekfree"); ,这里的y只能取0~8
//-------------------------------------------------------------------------------------------------------------------
void lcd_showstr(uint16 x, uint16 y, uint8 dat[])
{
	unsigned int j;
//	x *= POINT_SIZE, y *= POINT_SIZE;

	j = 0;
	while (dat[j] != '\0')
	{
		lcd_showchar(x + 8 * j, y * 16, dat[j]);
		j++;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示8位有符号
//  @param      x     	        坐标x方向的起点  参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点  参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的变量，数据类型int8
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showint8(0,0,x);//x为int8类型,y取值范围0~8
//-------------------------------------------------------------------------------------------------------------------
void lcd_showint8(uint16 x, uint16 y, char dat)
{
	unsigned char a[3];
	unsigned char i;
//	x *= POINT_SIZE, y *= POINT_SIZE;

	if (dat < 0)
	{
		lcd_showchar(x, y * 16, '-');
		dat = -dat;
	}
	else	lcd_showchar(x, y * 16, ' ');

	a[0] = dat / 100;
	a[1] = dat / 10 % 10;
	a[2] = dat % 10;
	i = 0;
	while (i < 3)
	{
		lcd_showchar(x + (8 * (i + 1)), y * 16, '0' + a[i]);
		i++;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示8位无符号
//  @param      x     	        坐标x方向的起点 参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点 参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的变量，数据类型uint8
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showuint8(0,0,x);//x为uint8类型
//-------------------------------------------------------------------------------------------------------------------
void lcd_showuint8(uint16 x, uint16 y, unsigned char dat)
{
	unsigned char a[3];
	unsigned char i;
//	x *= POINT_SIZE, y *= POINT_SIZE;

	a[0] = dat / 100;
	a[1] = dat / 10 % 10;
	a[2] = dat % 10;
	i = 0;
	while (i < 3)
	{
		lcd_showchar(x + (8 * i), y * 16, '0' + a[i]);
		i++;
	}

}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示16位有符号
//  @param      x     	        坐标x方向的起点 参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点 参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的变量，数据类型int16
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showint16(0,0,x);//x为int16类型
//-------------------------------------------------------------------------------------------------------------------
void lcd_showint16(uint16 x, uint16 y, int16 dat)
{
	unsigned char a[5];
	unsigned char i;
//	x *= POINT_SIZE, y *= POINT_SIZE;

	if (dat < 0)
	{
		lcd_showchar(x, y * 16, '-');
		dat = -dat;
	}
	else	lcd_showchar(x, y * 16, ' ');

	a[0] = dat / 10000;
	a[1] = dat / 1000 % 10;
	a[2] = dat / 100 % 10;
	a[3] = dat / 10 % 10;
	a[4] = dat % 10;

	i = 0;
	while (i < 5)
	{
		lcd_showchar(x + (8 * (i + 1)), y * 16, '0' + a[i]);
		i++;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示16位无符号
//  @param      x     	        坐标x方向的起点 参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点 参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的变量，数据类型uint16
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showuint16(0,0,x);//x为uint16类型
//-------------------------------------------------------------------------------------------------------------------
void lcd_showuint16(uint16 x, uint16 y, uint16 dat)
{
	unsigned char a[5];
	unsigned char i;
//	x *= POINT_SIZE, y *= POINT_SIZE;

	a[0] = dat / 10000;
	a[1] = dat / 1000 % 10;
	a[2] = dat / 100 % 10;
	a[3] = dat / 10 % 10;
	a[4] = dat % 10;

	i = 0;
	while (i < 5)
	{
		lcd_showchar(x + (8 * i), y * 16, '0' + a[i]);
		i++;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//  @brief      液晶显示浮点数(去除整数部分无效的0)
//  @param      x     	        坐标x方向的起点 参数范围 0 -（TFT_X_MAX-1）
//  @param      y     	        坐标y方向的起点 参数范围 0 -（TFT_Y_MAX/16-1）
//  @param      dat       	    需要显示的变量，数据类型float或double
//  @param      num       	    整数位显示长度   最高10位  
//  @param      pointnum        小数位显示长度   最高6位
//  @return     void
//  @since      v1.0
//  Sample usage:               lcd_showfloat(0,0,x,2,3);//显示浮点数   整数显示2位   小数显示三位
//  @note                       特别注意当发现小数部分显示的值与你写入的值不一样的时候，
//                              可能是由于浮点数精度丢失问题导致的，这并不是显示函数的问题，
//                              有关问题的详情，请自行百度学习   浮点数精度丢失问题。
//                              负数会显示一个 ‘-’号   正数显示一个空格
//-------------------------------------------------------------------------------------------------------------------
void lcd_showfloat(uint16 x, uint16 y, double dat, uint8 num, uint8 pointnum)
{
    uint8   length;
    int8    buff[34];
    int8    start, end, point;

    if (6 < pointnum)  pointnum = 6;
    if (10 < num)      num = 10;

    if (0 > dat)   length = zf_sprintf(&buff[0], "%f", dat);//负数
    else
    {
        length = zf_sprintf(&buff[1], "%f", dat);
        length++;
    }
    point = length - 7;         //计算小数点位置
    start = point - num - 1;    //计算起始位
    end = point + pointnum + 1; //计算结束位
    while (0 > start)//整数位不够  末尾应该填充空格
    {
        buff[end] = ' ';
        end++;
        start++;
    }

    if (0 > dat)   buff[start] = '-';
    else        buff[start] = ' ';

    buff[end] = '\0';

    lcd_showstr(x, y, (uint8*)buff);	//显示数字
}